package cn.wenzy.aurora.framework.configuration;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.wenzy.aurora.framework.converter.FastJson2HttpMessageConverter;
import cn.wenzy.aurora.framework.support.i18n.serializer.I18nContextValueFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

@Slf4j
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {

    @Autowired
    private  I18nContextValueFilter i18nContextValueFilter;

    @Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
        // 处理Content-Type 为 “application/x-www-form-urlencoded”
        converters.add(new FormHttpMessageConverter());
        converters.add(new ByteArrayHttpMessageConverter());
        // 处理字符串, 避免直接返回字符串的时候被添加了引号
        StringHttpMessageConverter smc = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        converters.add(smc);
        // 使用fastjson处理返回数据
        converters.add(new FastJson2HttpMessageConverter(i18nContextValueFilter));
    }

    /**
     * spring mvc的配置，处理添加spring security后，swagger页面访问不了的问题
     * @param registry
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        String[] staticResourceLocations = {
                "classpath:/META-INF/resources/",
                "classpath:/resources/",
                "classpath:/static/",
                "classpath:/public/"
        };
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        registry.addResourceHandler("/**").addResourceLocations(staticResourceLocations);
        // 设置静态资源url前置和资源路径
        registry.addResourceHandler("/static/**").addResourceLocations(staticResourceLocations);
    }

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        Map<String, HandlerInterceptor> handlerInterceptorMap = SpringUtil.getBeansOfType(HandlerInterceptor.class);
        if (MapUtil.isNotEmpty(handlerInterceptorMap)){
            for (Map.Entry<String, HandlerInterceptor> entry : handlerInterceptorMap.entrySet()){
                log.info("interceptor: {}", entry.getKey());
                HandlerInterceptor handlerInterceptor = entry.getValue();
                int order = getSort(handlerInterceptor);
                registry.addInterceptor(handlerInterceptor).order(order);
            }
        }
        super.addInterceptors(registry);
    }

    /**
     * 获取顺序号，先判断注解@Order，再判断Ordered的接口，如果有注解就不再判断接口
     * @param obj
     * @return
     */
    private int getSort(Object obj) {
        Order orderAnnotation = AnnotationUtil.getAnnotation(obj.getClass(), Order.class);
        if (ObjectUtil.isNotNull(orderAnnotation)) {
            return orderAnnotation.value();
        }
        if (obj instanceof Ordered) {
            Ordered ordered = (Ordered) obj;
            return ordered.getOrder();
        }
        return 0;
    }
}
